package cn.bearspark.user.provider.dao.buffer;

import cn.bearspark.common.util.ConvertInfoUtil;
import cn.bearspark.framework.redis.starter.buffer.hash.un.RedisHashBuffer;
import cn.bearspark.user.dto.UserSimpleDTO;
import cn.bearspark.user.dto.UserSlimDTO;
import cn.bearspark.user.provider.dao.co.UserCO;
import cn.bearspark.user.provider.dao.key.UserBufferKeyBuilder;
import cn.bearspark.user.provider.dao.mapper.UserBaseMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户数据的缓存器
 *
 * @author f
 */
@Component
public class UserHashBuffer extends RedisHashBuffer<UserCO> {

    /**
     * 设置用户数据的缓存的有效期（单位：s），默认是 10min
     */
    private static final int USER_INFO_CACHE_EXPIRE = 60 * 10;

    /**
     * 用户简单信息的字段名集合，这些字段名是 UserCO 中的字段名
     */
    private final List<String> simpleInfoFieldNameList;

    /**
     * 用户最简信息的字段名集合，这些字段名是 UserCO 中的字段名
     */
    private final List<String> slimInfoFieldNameList;

    /**
     * 用户名的字段名
     */
    private final List<String> usernameFieldNameList;

    public UserHashBuffer(RedisTemplate<String, Object> redisTemplate,
                          UserBufferKeyBuilder userBufferKeyBuilder,
                          UserBaseMapper userBaseMapper) {
        super(
                redisTemplate,
                userBufferKeyBuilder,
                USER_INFO_CACHE_EXPIRE,
                UserCO.class,
                userBaseMapper
        );

        // 加 happeningNum 是为了防止查询缺失的热数据
        this.simpleInfoFieldNameList = List.of("userId", "username", "avatarUrl", "happeningNum");
        this.slimInfoFieldNameList = List.of("userId", "username", "avatarUrl", "happeningNum");
        this.usernameFieldNameList = List.of("username", "happeningNum");
    }

    /**
     * 查询指定用户的最简信息
     *
     * @param userId 指定的用户 id
     * @return 指定用户的最简信息
     */
    public UserSlimDTO getSlimInfo(long userId) {
        return listSlimInfo(List.of(userId)).get(0);
    }

    /**
     * 查询指定用户的简单信息
     *
     * @param userIdList 指定的用户 id 集合
     * @return 指定用户的简单信息集合
     */
    public List<UserSimpleDTO> listSimpleInfo(List<Long> userIdList) {
        Map<Long, UserCO> userCOMap = super.mapLess(userIdList, simpleInfoFieldNameList);

        return userIdList.stream().map(followerId ->
                ConvertInfoUtil.convert(userCOMap.get(followerId), UserSimpleDTO.class)
        ).collect(Collectors.toCollection(ArrayList::new));
    }

    /**
     * 查询指定用户的最简信息
     *
     * @param userIdList 指定的用户 id 集合
     * @return 指定用户的最简信息集合
     */
    public List<UserSlimDTO> listSlimInfo(List<Long> userIdList) {
        Map<Long, UserCO> userCOMap = super.mapLess(userIdList, slimInfoFieldNameList);

        return userIdList.stream().map(followerId ->
                ConvertInfoUtil.convert(userCOMap.get(followerId), UserSlimDTO.class)
        ).toList();
    }

    /**
     * 获取指定用户的最简信息
     * <p>
     * 注意：本方法只会返回动态数不为 0 的用户
     *
     * @param userIdList 指定的用户 id 集合
     * @return 指定用户的最简信息，不包含动态数为 0 的用户
     */
    public List<UserSlimDTO> listSlimInfoWithHappening(List<Long> userIdList) {
        Map<Long, UserCO> userCOMap = super.mapLess(userIdList, slimInfoFieldNameList);
        return userIdList.stream()
                .map(userCOMap::get)
                .filter(userCO -> userCO.getHappeningNum() != 0)
                .map(userCO -> ConvertInfoUtil.convert(userCO, UserSlimDTO.class))
                .collect(Collectors.toCollection(ArrayList::new));
    }

    /**
     * 查询指定用户的最简信息
     *
     * @param userIdSet 指定的用户 id 集合
     * @return 指定用户的最简信息映射，key：用户 id，value：用户最简信息
     */
    public Map<Long, UserSlimDTO> mapUserSlimInfo(Set<Long> userIdSet) {
        return super.mapLess(userIdSet, slimInfoFieldNameList).entrySet().stream().collect(Collectors.toMap(
                Map.Entry::getKey,
                entry -> ConvertInfoUtil.convert(entry.getValue(), UserSlimDTO.class)
        ));
    }

    /**
     * 获取用户 id 与用户名的映射
     *
     * @param userIdSet 待查询的用户 id 集合
     * @return 用户 id 与用户名的映射，key：用户 id，value：用户名
     */
    public Map<Long, String> mapUsername(Set<Long> userIdSet) {
        return super.mapLess(userIdSet, usernameFieldNameList).entrySet().stream().collect(Collectors.toMap(
                Map.Entry::getKey,
                entry -> entry.getValue().getUsername()
        ));
    }
}
